package cn.com.surker.common;

import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.cache.interceptor.SimpleKey;
import org.springframework.stereotype.Component;

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;

@Component("cxEhCacheKeyGenerator")
public class CxEhCacheKeyGenerator implements KeyGenerator {

	@Override
	public Object generate(Object target, Method method, Object... params) {
		if (params == null || params.length == 0) {
			return SimpleKey.EMPTY;
		}
		StringBuilder str = new StringBuilder();
		boolean firstParam = true;

		for (Object param : params) {
			if (!firstParam) {
				str.append('_'); // 参数之间的分隔符
			}
			firstParam = false;

			// 处理数组类型
			if (param != null && param.getClass().isArray()) {
				appendArray(str, param);
			}
			// 处理Map类型
			else if (param instanceof Map) {
				appendMapKeys(str, (Map<?, ?>) param);
			}
			// 处理Collection类型
			else if (param instanceof Collection) {
				appendCollection(str, (Collection<?>) param);
			}
			// 处理其他类型
			else {
				str.append(toString(param));
			}
		}
		Object r = (str.length() == 0) ? SimpleKey.EMPTY : str.toString();
		return r;
	}

	// 处理数组：循环每个元素
	private void appendArray(StringBuilder sb, Object array) {
		int length = Array.getLength(array);
		for (int i = 0; i < length; i++) {
			Object element = Array.get(array, i);
			if (i > 0) {
				sb.append(',');
			}
			sb.append(toString(element));
		}
	}

	// 处理Map：循环每个键
	private void appendMapKeys(StringBuilder sb, Map<?, ?> map) {
		int index = 0;
		for (Object key : map.keySet()) {
			if (index++ > 0) {
				sb.append(',');
			}
			sb.append(toString(key));
		}
	}

	// 处理Collection：循环每个元素
	private void appendCollection(StringBuilder sb, Collection<?> collection) {
		int index = 0;
		for (Object element : collection) {
			if (index++ > 0) {
				sb.append(',');
			}
			sb.append(toString(element));
		}
	}

	// 安全转换为字符串（处理null）
	private String toString(Object obj) {
		return (obj == null) ? "null" : obj.toString();
	}
}
